package com.util;

import java.nio.charset.Charset;

/**
 * 处理由于mysql配置字符编码utf8 general ci， 而应用会接受utf8-mb4字节的情况
 */
public class UTF8MB4 {
    private final static Charset UTF8 = Charset.forName("UTF-8");

    /**
     * 判断字符串中是否存在4字节字符
     *
     * @param input 输入字符串
     * @return 包含4字节返回true， 否则为false
     */
    public static boolean containsMb4Char(String input) {
        if (input == null) {
            return false;
        }
        byte[] bytes = input.getBytes(UTF8);
        for (int i = 0; i < bytes.length; i++) {
            byte b = bytes[i];
            //four bytes
            if ((b & 0XF0) == 0XF0) {
                return true;
            } else if ((b & 0XE0) == 0XE0) {
                //three bytes
                //forward 2 byte
                i += 2;
            } else if ((b & 0XC0) == 0XC0) {
                i += 1;
            }
        }
        return false;
    }

    /**
     * 替换可能存在的utf8 4字节字符
     *
     * @param input       输入字符串
     * @param replacement 替换为的字符串
     * @return 替换后的utf8字符串
     */
    public static String replaceMb4Char(String input, String replacement) {
        if (input == null) {//为空直接返回
            throw new IllegalArgumentException("input can not be null when replaceMb4Char");
        }
        if(!containsMb4Char(input)){//不包含四字节的utf8mb4字符,直接返回原值
            return input;
        }
        //包含四字节的utf8mb4字符
        StringBuilder sb = new StringBuilder(input.length());
        byte[] bytes = input.getBytes(UTF8);
        char[] chars = input.toCharArray();
        int charIdx = 0;
        for (int i = 0; i < bytes.length; i++) {
            byte b = bytes[i];
            //four bytes
            if ((b & 0XF0) == 0XF0) {
                sb.append(replacement);
                //utf-8四字节字符unicode后变为2个字符， 故字符下标多加1
                charIdx += 2;
                i += 3;
                continue;
            } else if ((b & 0XE0) == 0XE0) {
                //three bytes
                //forward 2 byte
                i += 2;
            } else if ((b & 0XC0) == 0XC0) {
                i += 1;
            }
            sb.append(chars[charIdx]);
            charIdx++;
        }
        return sb.toString();
    }
}
